package com.tiancheng.onecode.service.impl;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tiancheng.onecode.configuration.MiniAppProperties;
import com.tiancheng.onecode.convert.OrderConvert;
import com.tiancheng.onecode.entity.*;
import com.tiancheng.onecode.enums.ClientSourceEnums;
import com.tiancheng.onecode.enums.MerchantStatusEnums;
import com.tiancheng.onecode.enums.MiniAppTypeEnum;
import com.tiancheng.onecode.enums.OrderStatusEnum;
import com.tiancheng.onecode.exception.AssertException;
import com.tiancheng.onecode.exception.Asserts;
import com.tiancheng.onecode.mapper.MemberOrderMapper;
import com.tiancheng.onecode.model.dto.PayMerchantDTO;
import com.tiancheng.onecode.model.dto.PayPlatformDTO;
import com.tiancheng.onecode.model.request.admin.QueryOrderReq;
import com.tiancheng.onecode.model.request.admin.StatisticsMerchantOrderReq;
import com.tiancheng.onecode.model.request.admin.StatisticsUserOrderReq;
import com.tiancheng.onecode.model.request.api.PayOrderRequest;
import com.tiancheng.onecode.model.response.PageInfo;
import com.tiancheng.onecode.model.response.Result;
import com.tiancheng.onecode.model.response.admin.*;
import com.tiancheng.onecode.model.response.api.OrderPayApiRes;
import com.tiancheng.onecode.model.response.api.QueryMerchantApiRes;
import com.tiancheng.onecode.model.response.api.QueryOrderDetailApiRes;
import com.tiancheng.onecode.mq.CancelOrderSender;
import com.tiancheng.onecode.service.*;
import com.tiancheng.onecode.trade.TradeApiClient;
import com.tiancheng.onecode.trade.enums.*;
import com.tiancheng.onecode.trade.model.SettlementRuleResVO;
import com.tiancheng.onecode.trade.model.request.order.*;
import com.tiancheng.onecode.trade.model.response.OpenOrderPrePayResVO;
import com.tiancheng.onecode.trade.model.response.OpenVerificationResVO;
import com.tiancheng.onecode.trade.notify.PayResultOrderBO;
import com.tiancheng.onecode.trade.notify.PayResultSubOrderBO;
import com.tiancheng.onecode.trade.utils.MoneyUtil;
import com.tiancheng.onecode.trade.utils.OrderIdHelper;
import com.tiancheng.onecode.utils.DateTimeUtil;
import com.tiancheng.onecode.utils.MerchantContext;
import com.tiancheng.onecode.utils.cache.SettleRulesCache;
import com.tiancheng.onecode.utils.lock.Lock;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.ListUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: kellen
 * @Description: 会员订单 service impl
 * @Date: create in 2024/12/9 18:22
 */
@Slf4j
@Service
@AllArgsConstructor
public class MemberOrderServiceImpl extends ServiceImpl<MemberOrderMapper, MemberOrder> implements IMemberOrderService {

    @Resource
    private IMemberSubOrderService memberSubOrderService;
    @Resource
    private IPlatformMerchantSettleRuleService platformMerchantSettleRuleService;
    @Resource
    private IPlatformService platformService;
    @Resource
    private IMemberOrderRefundService memberOrderRefundService;
    @Resource
    private IBillService IBillService;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private IMerchantService merchantService;
    @Resource
    private OrderIdHelper orderIdHelper;
    @Resource
    private MiniAppProperties miniAppProperties;
    @Resource
    private TradeApiClient tradeApiClient;
    @Resource
    private CancelOrderSender cancelOrderSender;
    @Resource
    private SettleRulesCache settleRulesCache;
    @Resource
    private IMerchantVoiceDeviceService merchantVoiceDeviceService;

    @Override
    public OrderPayApiRes pay(PayOrderRequest payOrderRequest) {
        final boolean b = MoneyUtil.judgeTwoDecimal(payOrderRequest.getAmount());
        Asserts.isTrue(b, "金额异常！");
        // 转换金额单位到分
        final int amount = payOrderRequest.getAmount().multiply(new BigDecimal(100)).intValue();
        Asserts.isTrue(amount >= 0, "请输入金额！");
        Asserts.isTrue(amount <= 2000000, "金额最大不超过2万！");
        final Optional<ClientSourceEnums> clientSourceEnums = ClientSourceEnums.getByCode(payOrderRequest.getClientSource());
        Asserts.isTrue(clientSourceEnums.isPresent(), "暂不支持的付款来源！");
        if (clientSourceEnums.get().equals(ClientSourceEnums.wechat_mini)) {
            Asserts.isTrue(StringUtils.isNotEmpty(payOrderRequest.getOpenId()), "请登录微信！");
        }
        final PayMerchantDTO payMerchantDTO = merchantService.queryPayMerchant(payOrderRequest.getPlatformMerchantId());
        Asserts.isTrue(Objects.nonNull(payMerchantDTO) && StringUtils.isNotEmpty(payMerchantDTO.getQr()), "该商户配置异常，请联系管理员处理！");
        Asserts.isTrue(payMerchantDTO.getMerchantStatus().equals(MerchantStatusEnums.normal.getCode()), "该商户当前不允许交易！");
        MiniAppProperties.MiniAppInfo miniAppInfo = getMiniAppInfo(clientSourceEnums, payMerchantDTO);
        // 有效期,单位s
        long expiration = miniAppProperties.getOrderExpire();
        final OpenCreateOrderBaseVO orderBaseVO = new OpenCreateOrderBaseVO();
        orderBaseVO.setOrderId(orderIdHelper.getOrderId(payMerchantDTO.getTradeIdPre(), payOrderRequest.getUserId()));
        orderBaseVO.setOriginalOrderId("0");
        orderBaseVO.setUid(payOrderRequest.getUserId());
        orderBaseVO.setMobile("");
        orderBaseVO.setOrderScene(OrderSceneEnum.miniapp.getCode());// 小程序
        orderBaseVO.setOrderName(payMerchantDTO.getMerchantName());
        orderBaseVO.setTradeInfo("{}");
        orderBaseVO.setOpenid(payOrderRequest.getOpenId());
        orderBaseVO.setCreateTime(LocalDateTime.now());
        orderBaseVO.setPayExpiryTime(LocalDateTime.now().plusSeconds(expiration));
        orderBaseVO.setOrderType("common");// 普通订单
        orderBaseVO.setOrderSource(OrderSourceEnum.ONE_CODE.getCode());// 订单来源，6-一码通
        orderBaseVO.setNotifyUrl(miniAppProperties.getNotifyUrl() + "notify/payCallback");

        final List<OpenCreateSubOrderVO> openCreateSubOrderVOS = new ArrayList<>();
        final OpenCreateSubOrderVO openCreateSubOrderVO = new OpenCreateSubOrderVO();
        openCreateSubOrderVO.setSubOrderId(orderBaseVO.getOrderId() + "01");
        openCreateSubOrderVO.setOriginalSubOrderId("0");
        openCreateSubOrderVO.setMerchantCode(payMerchantDTO.getTradeMerchantCode());
        openCreateSubOrderVO.setMerchantName(payMerchantDTO.getMerchantName());
        openCreateSubOrderVO.setProductCode(payMerchantDTO.getTradeMerchantCode());
        openCreateSubOrderVO.setProductName(payMerchantDTO.getMerchantName());
        openCreateSubOrderVO.setProductDetail(payMerchantDTO.getMerchantName());
        openCreateSubOrderVO.setProductCount(1);
        openCreateSubOrderVO.setProductCost(amount);
        openCreateSubOrderVO.setSubOrderAmount(amount);
        openCreateSubOrderVOS.add(openCreateSubOrderVO);
        orderBaseVO.setSubOrders(openCreateSubOrderVOS);
        // 主订单信息
        MemberOrder order = OrderConvert.INSTANCE.convert(orderBaseVO);
        Asserts.isTrue(null != order, "下单失败！");
        if (clientSourceEnums.get().equals(ClientSourceEnums.wechat_mini)) {
            // 微信小程序
            order.setPayWay(PayWayEnum.WECHAT.getCode());
        } else if (clientSourceEnums.get().equals(ClientSourceEnums.alipay_mini)) {
            order.setPayWay(PayWayEnum.ALIPAY.getCode());
        } else if (clientSourceEnums.get().equals(ClientSourceEnums.union_mini)) {
            order.setPayWay(PayWayEnum.UNIONPAY.getCode());
        }
        order.setOrderId(orderBaseVO.getOrderId());
        order.setUserId(payOrderRequest.getUserId());
        order.setOrderName(payMerchantDTO.getMerchantName());
        order.setPayScene("miniapp");
        order.setCreatedDt(LocalDateTime.now());
        order.setDiscount(0);
        order.setIsCoupon(0);
        order.setAppId(miniAppInfo.getAppid());
        order.setOrderStatus(OrderStatusEnum.waiting_pay.getCode());
        order.setPayStatus(OrderPayStatusEnum.un_pay.getCode());
        order.setOrderAmount(orderBaseVO.getSubOrders().stream().mapToInt(OpenCreateSubOrderVO::getSubOrderAmount).sum());
        order.setPayAmount(0);
        order.setIsCoupon(0);
        order.setDiscount(0);
        order.setPlatformCode(payMerchantDTO.getPlatformCode());
        order.setPlatformMerchantId(payMerchantDTO.getPlatformMerchantId());
        // 子订单
        List<MemberSubOrder> subOrders = OrderConvert.INSTANCE.convert(openCreateSubOrderVOS);
        Asserts.isTrue(CollectionUtils.isNotEmpty(subOrders), "下单失败！");

        SettlementRuleResVO settleRules = settleRulesCache.getRuleByPlatformMerchantId(payMerchantDTO.getPlatformMerchantId());
        Asserts.isTrue(null != settleRules, "下单失败，未配置商户清分信息！！");
        subOrders.forEach(s -> {
            s.setSettleRuleCode(settleRules.getSettleRuleCode());
            s.setMerchantCode(StringUtils.isNotEmpty(payMerchantDTO.getMerchantCode()) ? payMerchantDTO.getMerchantCode() : payMerchantDTO.getTradeMerchantCode());
            s.setOrderId(orderBaseVO.getOrderId());
            s.setCreatedDt(LocalDateTime.now());
            s.setOrderSource(order.getOrderScene());
            s.setPayAmount(0);
            s.setIsCoupon(0);
            s.setDiscount(0);
            s.setSubOrderStatus(order.getOrderStatus());
            s.setVerificationStatus("");
            s.setPlatformMerchantId(order.getPlatformMerchantId());
        });
        try (Lock lock = new Lock(Lock.LOCK_ORDER_PAY, order.getUserId(), 5, 5)) {
            Asserts.isTrue(lock.getLockRes(), "下单失败，请稍后再试！");
            final OrderPayApiRes result = transactionTemplate.execute(transactionStatus -> {
                try {
                    // 调用交易中台下单
                    tradeApiClient.createOrder(orderBaseVO);
                    // 调用交易中台支付接口
                    final OpenOrderPayVO openOrderPayVO = new OpenOrderPayVO();
                    openOrderPayVO.setOrderId(orderBaseVO.getOrderId());
                    openOrderPayVO.setUid(payOrderRequest.getUserId());
                    openOrderPayVO.setOpenid(payOrderRequest.getOpenId());
                    openOrderPayVO.setSubAppId(miniAppInfo.getAppid());
                    openOrderPayVO.setPayWay(order.getPayWay());
                    openOrderPayVO.setPayScene("miniapp");
                    OpenOrderPrePayResVO payResVO = tradeApiClient.pay(openOrderPayVO);
                    Asserts.isNotNull(payResVO, "支付失败！");
                    OrderPayApiRes orderPayApiRes = new OrderPayApiRes();
                    orderPayApiRes.setOrderId(order.getOrderId());
                    orderPayApiRes.setOrderName(order.getOrderName());
                    orderPayApiRes.setPayWay(order.getPayWay());
                    orderPayApiRes.setOrderAmount(order.getOrderAmount());
                    orderPayApiRes.setPayExpiryTime(order.getPayExpiryTime());
                    orderPayApiRes.setPayScene(order.getPayScene());
                    orderPayApiRes.setPayInfo(payResVO.getPayInfo());
                    // 保存主订单
                    this.save(order);
                    //保存子订单
                    memberSubOrderService.saveBatch(subOrders);
                    setUpOrderTimeout(order);
                    return orderPayApiRes;
                } catch (Exception e) {
                    transactionStatus.setRollbackOnly();
                    throw e;
                }
            });
            return result;
        } catch (AssertException e) {
            throw e;
        } catch (Exception e) {
            log.error("一码通下单支付报错：", e);
            throw new AssertException(500, "下单超时，请稍后再试！");
        }

    }

    private MiniAppProperties.MiniAppInfo getMiniAppInfo(Optional<ClientSourceEnums> clientSourceEnums, PayMerchantDTO payMerchantDTO) {
        MiniAppProperties.MiniAppInfo miniAppInfo;
        if (clientSourceEnums.get().equals(ClientSourceEnums.wechat_mini)) {
            miniAppInfo = miniAppProperties.getMiniAppInfo(payMerchantDTO.getPlatformCode(), MiniAppTypeEnum.wechat_c);
        } else if (clientSourceEnums.get().equals(ClientSourceEnums.alipay_mini)) {
            miniAppInfo = miniAppProperties.getMiniAppInfo(payMerchantDTO.getPlatformCode(), MiniAppTypeEnum.alipay_c);
        } else {
            miniAppInfo = miniAppProperties.getMiniAppInfo(payMerchantDTO.getPlatformCode(), MiniAppTypeEnum.union_c);
        }
        return miniAppInfo;
    }

    @Override
    public MemberOrder queryByOrderId(String orderId) {
        return this.getOne(new LambdaQueryWrapper<MemberOrder>().eq(MemberOrder::getOrderId, orderId));
    }

    @Override
    public PageInfo<QueryOrderRes> queryPlatformPage(QueryOrderReq params) {
        IPage<MemberOrder> page = new Page<>(params.getCurrentPage(), params.getPageSize());
        if (null != params.getCreateDtBegin()) {
            params.setCreateDtBegin(LocalDateTime.of(LocalDate.from(params.getCreateDtBegin()), LocalDateTime.MIN.toLocalTime()));
        }
        if (null != params.getCreateDtEnd()) {
            params.setCreateDtEnd(LocalDateTime.of(LocalDate.from(params.getCreateDtEnd()), LocalDateTime.MAX.toLocalTime()));
        }
        final IPage<QueryOrderRes> pageResult = this.baseMapper.queryPage(page, params);
        if (CollectionUtils.isNotEmpty(pageResult.getRecords())) {
            List<PlatformQueryRes> platformQueryRes = platformService.queryByPlatformCodes(pageResult.getRecords().stream().map(QueryOrderRes::getPlatformCode).collect(Collectors.toSet()));
            if (CollectionUtils.isNotEmpty(platformQueryRes)) {
                for (QueryOrderRes record : pageResult.getRecords()) {
                    platformQueryRes.stream().filter(p -> p.getPlatformCode().equals(record.getPlatformCode())).findFirst().ifPresent(p -> {
                        record.setPayChannelName(p.getPaymentChannelName());
                    });

                }
            }
        }
        return new PageInfo<>(pageResult.getCurrent(), pageResult.getSize(), pageResult.getTotal(), pageResult.getRecords());
    }

    @Override
    public QueryOrderDetailRes queryOrderDetail(String orderId) {
        final MemberOrder memberOrder = this.queryByOrderId(orderId);
        Asserts.isTrue(null != memberOrder, "未查询到订单：" + orderId);
        final List<MemberSubOrder> memberSubOrders = memberSubOrderService.queryByOrderId(memberOrder.getOrderId());
        Asserts.isTrue(!CollectionUtils.isEmpty(memberSubOrders), "未查询到订单：" + orderId);
        final QueryOrderDetailRes queryOrderDetailRes = new QueryOrderDetailRes();
        queryOrderDetailRes.setOrderId(memberOrder.getOrderId());
        queryOrderDetailRes.setFlowId(memberOrder.getFlowId());
        queryOrderDetailRes.setPayStatus(memberOrder.getPayStatus());
        queryOrderDetailRes.setPayTime(memberOrder.getPayTime());
        queryOrderDetailRes.setPlatformCode(memberOrder.getPlatformCode());
        queryOrderDetailRes.setPayScene(memberOrder.getPayScene());
        queryOrderDetailRes.setPayWay(memberOrder.getPayWay());
        queryOrderDetailRes.setMerchantCode(memberSubOrders.get(0).getMerchantCode());
        queryOrderDetailRes.setMerchantName(memberSubOrders.get(0).getMerchantName());
        queryOrderDetailRes.setSubOrderAmount(memberSubOrders.get(0).getSubOrderAmount());
        queryOrderDetailRes.setSubOrderAmount(memberSubOrders.get(0).getSubOrderAmount());
        queryOrderDetailRes.setPayAmount(memberSubOrders.get(0).getPayAmount());
        queryOrderDetailRes.setSubOrderStatus(memberSubOrders.get(0).getSubOrderStatus());
        queryOrderDetailRes.setUserId(memberOrder.getUserId());

        // 获取清分规则
        final PlatformMerchantSettleRule settleRule = platformMerchantSettleRuleService.queryByCode(memberSubOrders.get(0).getSettleRuleCode());
        queryOrderDetailRes.setRuleCode(memberSubOrders.get(0).getSettleRuleCode());
        if (null != settleRule) {
            queryOrderDetailRes.setPlatformPercent(settleRule.getPlatformPercent());
        }
        final PlatformQueryRes platformQueryRes = platformService.queryByPlatformCode(memberOrder.getPlatformCode());
        if (null != platformQueryRes) {
            // 获取支付通道信息
            queryOrderDetailRes.setPayChannel(platformQueryRes.getPaymentChannelName());
        }
        // 查询退款单信息
        final List<MemberOrderRefund> memberOrderRefunds = memberOrderRefundService.queryByOrderId(memberOrder.getOrderId());
        if (!CollectionUtils.isEmpty(memberOrderRefunds)) {
            queryOrderDetailRes.setRefundIds(memberOrderRefunds.stream().map(MemberOrderRefund::getRefundId).collect(Collectors.toList()));
        }
        return queryOrderDetailRes;
    }

    @Override
    public List<StatisticsMerchantOrderPayRes> statisticsByMerchant(StatisticsMerchantOrderReq statisticsMerchantOrderReq) {
        return this.baseMapper.statisticsByMerchant(statisticsMerchantOrderReq);
    }

    @Override
    public void payResultHandler(PayResultOrderBO payResultOrderBO) {
        final MemberOrder order = this.queryByOrderId(payResultOrderBO.getOrderId());
        if (null == order) {
            log.error("未查询到订单：{}", payResultOrderBO.getOrderId());
            return;
        }
        if (StringUtils.isNotEmpty(order.getPayStatus()) && order.getPayStatus().equals(OrderPayStatusEnum.paid.getCode())) {
            // 订单已支付，重复回调，返回
            log.error("订单状态为已支付，重复回调，返回！订单号：{}", payResultOrderBO.getOrderId());
            return;
        }
        final MemberOrder updateOrder = new MemberOrder();
        updateOrder.setId(order.getId());
        updateOrder.setFlowId(payResultOrderBO.getFlowId());
        if (payResultOrderBO.getOrderStatus().equals("AP")) {
            updateOrder.setOrderStatus(OrderStatusEnum.paid.getCode());
        }

        updateOrder.setPayStatus(payResultOrderBO.getPayStatus());
        updateOrder.setPayAmount(payResultOrderBO.getPayAmount());
        updateOrder.setPayScene(payResultOrderBO.getPayScene());
        updateOrder.setPayWay(payResultOrderBO.getPayWay());
        updateOrder.setPayTime(null != payResultOrderBO.getPayTime() ? payResultOrderBO.getPayTime() : LocalDateTime.now());
        updateOrder.setIsCoupon(payResultOrderBO.getIsCoupon());
        updateOrder.setDiscount(payResultOrderBO.getDiscount());
        updateOrder.setLastUpdDt(LocalDateTime.now());

        final List<MemberSubOrder> memberSubOrders = memberSubOrderService.queryByOrderId(order.getOrderId());
        final List<MemberSubOrder> updateSubOrders = new ArrayList<>();
        for (MemberSubOrder memberSubOrder : memberSubOrders) {
            final MemberSubOrder updateMemberSubOrder = new MemberSubOrder();
            updateMemberSubOrder.setId(memberSubOrder.getId());
            updateMemberSubOrder.setLastUpdDt(LocalDateTime.now());
            updateMemberSubOrder.setSubOrderStatus(updateOrder.getOrderStatus());
            final Optional<PayResultSubOrderBO> first = payResultOrderBO.getSubOrders().stream().filter(ps -> ps.getSubOrderId().equals(memberSubOrder.getSubOrderId())).findFirst();
            if (first.isPresent()) {
                updateMemberSubOrder.setSubFlowId(first.get().getSubFlowId());
                updateMemberSubOrder.setPayAmount(first.get().getPayAmount());
                updateMemberSubOrder.setVerificationStatus(VerificationStatusEnum.WAIT.getCode());
                updateMemberSubOrder.setIsCoupon(first.get().getIsCoupon());
                updateMemberSubOrder.setDiscount(first.get().getDiscount());
                updateSubOrders.add(updateMemberSubOrder);
            }
        }

        final Boolean result = transactionTemplate.execute(transactionStatus -> {
            try {
                // 更新主订单
                this.updateById(updateOrder);
                //更新子订单
                if (!CollectionUtils.isEmpty(updateSubOrders)) {
                    memberSubOrderService.updateBatchById(updateSubOrders);
                }
                // 生成账单
                IBillService.createAfterPay(order.getOrderId());
                return true;
            } catch (Exception e) {
                transactionStatus.setRollbackOnly();
                throw e;
            }
        });
        Asserts.isTrue(null != result && result, "支付消息处理异常！");
        // 推送支付消息到云音响
        merchantVoiceDeviceService.payNotice(order.getPlatformMerchantId(), memberSubOrders.get(0).getMerchantName(), order.getOrderAmount());
    }

    @Override
    public Integer totalPayAmount(Long platformMerchantId) {
        return getBaseMapper().totalPayAmount(platformMerchantId);
    }

    @Override
    public Integer todayPayAmount(Long platformMerchantId) {
        return getBaseMapper().todayPayAmount(platformMerchantId);
    }

    @Override
    public QueryMerchantApiRes getMerchantInfo(Long platformMerchantId) {
        PayMerchantDTO andCacheMerchant = merchantService.queryPayMerchant(platformMerchantId);
        QueryMerchantApiRes merchantApiRes = new QueryMerchantApiRes();
        merchantApiRes.setPlatformMerchantId(platformMerchantId);
        merchantApiRes.setMerchantStatus(andCacheMerchant.getMerchantStatus());
        merchantApiRes.setPlatformCode(andCacheMerchant.getPlatformCode());
        merchantApiRes.setMerchantCode(andCacheMerchant.getMerchantCode());
        merchantApiRes.setMerchantName(andCacheMerchant.getMerchantName());
        return merchantApiRes;
    }

    @Override
    public QueryOrderDetailApiRes queryApiOrderDetail(String orderId) {
        QueryOrderDetailApiRes queryOrderDetailApiRes = getBaseMapper().queryApiOrderDetail(null, orderId);
        if (null != queryOrderDetailApiRes && StringUtils.isNotEmpty(queryOrderDetailApiRes.getSettleRuleCode())) {
            PlatformMerchantSettleRule platformMerchantSettleRule = platformMerchantSettleRuleService.queryByCode(queryOrderDetailApiRes.getSettleRuleCode());
            if (null != platformMerchantSettleRule) {
                queryOrderDetailApiRes.setPlatformPercent(platformMerchantSettleRule.getPlatformPercent());
            }

        }
        return queryOrderDetailApiRes;
    }

    @Transactional
    @Override
    public Boolean cancelOrder(String orderId) {
        MemberOrder order = this.queryByOrderId(orderId);
        if (order.getOrderStatus().equals(OrderStatusEnum.waiting_pay.getCode())) {
            // 只处理待支付状态下的订单
            OpenCancelOrderVO openCancelOrderVO = new OpenCancelOrderVO();
            openCancelOrderVO.setOrderId(orderId);
            PayPlatformDTO payPlatformDTO = platformService.getDefaultOne("default");
            MerchantContext.setPlatform(payPlatformDTO);
            Result result = tradeApiClient.closeOrder(openCancelOrderVO);
            if (result != null && result.getRet() == 0) {
                MerchantContext.clear();
                MemberOrder memberOrder = new MemberOrder();
                memberOrder.setId(order.getId());
                memberOrder.setOrderStatus(OrderStatusEnum.cancelled.getCode());
                memberOrder.setLastUpdDt(LocalDateTime.now());

                final MemberSubOrder memberSubOrder = new MemberSubOrder();
                memberSubOrder.setSubOrderStatus(OrderStatusEnum.cancelled.getCode());
                memberSubOrder.setLastUpdDt(LocalDateTime.now());
                memberSubOrderService.update(memberSubOrder, new LambdaQueryWrapper<MemberSubOrder>().eq(MemberSubOrder::getOrderId, orderId));
                return this.updateById(memberOrder);
            } else if (result != null && result.getRet() == 1 && result.getErrorCode().equals(1504)) {
                // 交易中台订单已支付
                log.info("交易中台订单已支付!订单号：{}", orderId);
                // TODO 是否调用一次查询接口修正一码通订单状态
            } else {
                // 订单关闭失败
                throw new RuntimeException("关闭订单失败，交易中台返回：" + result.getMsg());
            }
            return true;
        }
        return true;
    }

    @Override
    public void verification(String dateTime) {
        // 查询待核销的订单
        LocalDateTime toDayZeroTime = LocalDateTime.of(LocalDateTime.now().toLocalDate(), LocalTime.MAX);
        if (StringUtils.isNotEmpty(dateTime)) {
            toDayZeroTime = LocalDateTime.of(DateTimeUtil.string2LocalDateTime(dateTime, DateTimeUtil.bj_pattern).toLocalDate(), LocalTime.MAX);
        }
        final List<MemberSubOrder> memberSubOrders = memberSubOrderService.waitVerificationSubOrders(toDayZeroTime);
        if (CollectionUtils.isEmpty(memberSubOrders)) {
            // 当天无待核销订单
            log.info("当天无待核销订单,日期：{}", toDayZeroTime);
            return;
        }

        // TODO 后面如果有多平台的话这里改成从订单里面获取平台信息
        PayPlatformDTO payPlatformDTO = platformService.getDefaultOne("default");
        MerchantContext.setPlatform(payPlatformDTO);
        final List<List<MemberSubOrder>> partition = ListUtils.partition(memberSubOrders, 100);
        for (List<MemberSubOrder> subOrders : partition) {
            OpenVerificationOrderVO vo = new OpenVerificationOrderVO();
            vo.setSubOrderId(subOrders.stream().map(MemberSubOrder::getSubOrderId).collect(Collectors.toList()));
            final OpenVerificationResVO verification = tradeApiClient.verification(vo);
            if (verification != null) {
                // 核销成功的子订单
                final Set<String> successSubOrders = verification.getSuccessSubOrders();
                // 核销失败的子订单
                final Set<String> failSubOrders = verification.getSuccessSubOrders();
                if (CollectionUtils.isNotEmpty(successSubOrders)) {
                    final Set<Long> successIds = subOrders.stream().filter(s -> successSubOrders.contains(s.getSubOrderId())).map(MemberSubOrder::getId).collect(Collectors.toSet());
                    final MemberSubOrder updateEntity = new MemberSubOrder();
                    updateEntity.setLastUpdDt(LocalDateTime.now());
                    updateEntity.setVerificationStatus(VerificationStatusEnum.SC.getCode());
                    updateEntity.setVerificationTime(LocalDateTime.now());
                    memberSubOrderService.update(updateEntity, new LambdaQueryWrapper<MemberSubOrder>().in(MemberSubOrder::getId, successIds));

                    Bill bill = new Bill();
                    bill.setVerificationStatus(VerificationStatusEnum.SC.getCode());
                    bill.setVerificationTime(LocalDateTime.now());
                    IBillService.update(bill,new LambdaQueryWrapper<Bill>().in(Bill::getSubOrderId,successSubOrders));
                }
                if (CollectionUtils.isNotEmpty(failSubOrders)) {
                    final Set<Long> failIds = subOrders.stream().filter(s -> failSubOrders.contains(s.getSubOrderId())).map(MemberSubOrder::getId).collect(Collectors.toSet());
                    final MemberSubOrder updateEntity = new MemberSubOrder();
                    updateEntity.setLastUpdDt(LocalDateTime.now());
                    updateEntity.setVerificationStatus(VerificationStatusEnum.FL.getCode());
                    memberSubOrderService.update(updateEntity, new LambdaQueryWrapper<MemberSubOrder>().in(MemberSubOrder::getId, failIds));

                    Bill bill = new Bill();
                    bill.setVerificationStatus(VerificationStatusEnum.FL.getCode());
                    IBillService.update(bill,new LambdaQueryWrapper<Bill>().in(Bill::getSubOrderId,successSubOrders));
                }

            }
        }
        MerchantContext.clear();
    }

    @Override
    public List<StatisticsUserOrderItemRes> statisticsByUserId(StatisticsUserOrderReq statisticsUserOrderReq) {
        return this.getBaseMapper().statisticsByUserId(statisticsUserOrderReq);
    }

    @Override
    public List<StatisticsMerchantOrderPayRes> statisticsByDay(StatisticsMerchantOrderReq statisticsMerchantOrderReq) {
        return this.getBaseMapper().statisticsByDay(statisticsMerchantOrderReq);
    }

    /**
     * 设置关单超时
     *
     * @param paymentInfo
     */
    private void setUpOrderTimeout(MemberOrder paymentInfo) {
        //获取订单超时时间
        long delayTimes = miniAppProperties.getOrderExpire() * 1000;
        try {
            log.info("setUpOrderTimeout: producer cmq message = [{}]", JSON.toJSONString(paymentInfo));
            //发送延迟消息
            cancelOrderSender.sendMessage(JSON.toJSONString(paymentInfo), delayTimes);
        } catch (Exception e) {
            log.warn("setUpOrderTimeout: send cmq message failed", e);
        }
    }
}
